from flask import abort, jsonify
from flask import current_app
from flask import render_template, redirect, url_for, g
from flask import request

from info import db
from info.constants import USER_COLLECTION_MAX_NEWS, QINIU_DOMIN_PREFIX
from info.models import tb_user_collection, Category, News
from info.modules.user import user_blu
from info.utils.common import user_login_data, file_upload
from info.utils.response_code import RET, error_map


# 创建用户个人中心视图函数
@user_blu.route("/user_info")
@user_login_data
def user_info():
    """取出用户数据"""
    # 查询数据库数据
    user = g.user
    if not user:  # 未登录
        return redirect(url_for("home.index"))

    # 后端模板渲染
    return render_template("news/user.html", user=user.to_dict())


# 基本资料
@user_blu.route("/base_info", methods=["GET", "POST"])
@user_login_data
def base_info():
    user = g.user
    if not user:  # 判断用户登录
        return abort(403)

    # GET 展示数据
    if request.method == "GET":
        return render_template("news/user_base_info.html", user=user.to_dict())

    # POST 提交数据
    signature = request.json.get("signature")
    nick_name = request.json.get("nick_name")
    gender = request.json.get("gender")

    # 校验参数
    if not all([signature, nick_name, gender]):
        return jsonify(errno=RET.PARAMERR, errmsg=error_map[RET.PARAMERR])

    if gender not in ["MAN", "WOMAN"]:
        return jsonify(errno=RET.PARAMERR, errmsg=error_map[RET.PARAMERR])

    # 修改用户数据
    user.signature = signature
    user.nick_name = nick_name
    user.gender = gender

    # json返回结果
    return jsonify(errno=RET.OK, errmsg=error_map[RET.OK])
    # return redirect(url_for("user.base_info")) 这个个人资料的显示可以做 但是后端这样无法实现其它地方的数据的刷新（同步刷新的姓名等，不在一个资料页面上）


# 头像设置
@user_blu.route("/pic_info", methods=["GET", "POST"])
@user_login_data
def pic_info():
    user = g.user
    if not user:  # 判断用户是否登录
        return abort(403)

    # GET展示数据
    if request.method == "GET":
        return render_template("news/user_pic_info.html", user=user.to_dict())

    # POST 提交数据  获取用户传来的文件
    img_file = request.files.get("avatar")
    # 读取文件的二进制数据 检查有没有传文件
    try:
        img_bytes = img_file.read()
        # print(img_bytes)
    except BaseException as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.PARAMERR, errmsg=error_map[RET.PARAMERR])

    # TODO 要修改的地方  注册七牛云  暂用师
    # 一般文件的存取会使用文件服务器来操作，上传文件成功后，只需要该文件的访问url即可
    try:
        file_name = file_upload(img_bytes)
    except BaseException as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.THIRDERR, errmsg=error_map[RET.THIRDERR])
    # 记录头像url
    user.avatar_url = file_name

    # json返回结果
    # return jsonify(errno=RET.OK, errmsg=error_map[RET.OK])
    # json返回结果 为了让前端能够获取到最新的头像链接，返回用户信息
    return jsonify(errno=RET.OK, errmsg=error_map[RET.OK], data=user.to_dict())


# 密码设置
@user_blu.route("/pass_info", methods=['GET', 'POST'])
@user_login_data
def pass_info():
    user = g.user
    if not user:  # 判断用户登录
        return abort(403)

    # GET展示数据
    if request.method == "GET":
        # 返回静态页面  send_static_file是读取内容，里面文件的路径会改变
        return current_app.send_static_file("news/html/user_pass_info.html")

    # POST 提交数据 只需要获取就密码和新密码　确认密码本地校验就行
    old_password = request.json.get("old_password")
    new_password = request.json.get("new_password")
    if not all([old_password, new_password]):
        return jsonify(errno=RET.PARAMERR, errmsg=error_map[RET.PARAMERR])

    # 校验旧密码  在user中封装了校验密码
    if not user.check_password(old_password):  # 密码错误
        return jsonify(errno=RET.PARAMERR, errmsg=error_map[RET.PARAMERR])

    # 修改新密码
    user.password = new_password

    # 返回数据
    return jsonify(errno=RET.OK, errmsg=error_map[RET.OK])


# 我的收藏
@user_blu.route("/collection")
@user_login_data
def collection():
    user = g.user
    if not user:  # 判断用户是否登录
        return abort(403)

    # 获取参数获取请求的第几页  默认为1
    p = request.args.get("p", 1)
    # 校验参数
    try:
        p = int(p)
    except BaseException as e:
        current_app.logger.error(e)
        return abort(403)

    # 查询该用户收藏的所有新闻　收藏时间倒序  tb_user_collection收藏表变量 c.create_time.desc() 以收藏时间这列倒序。c是指列(因为是多对多关系，第三张表)
    try:
        # 分页pafinate(当前页，每页几条) 分页后是个pn对像
        pn = user.collection_news.order_by(tb_user_collection.c.create_time.desc()).paginate(p,
                                                                                             USER_COLLECTION_MAX_NEWS)
    except BaseException as e:
        current_app.logger.error(e)

    # 转换数据
    data = {
        "news_list": [news.to_dict() for news in pn.items],  # 取出所有数据放到列表中，传给页面遍历
        "cur_page": pn.page,  # 当前页码
        "total_page": pn.pages  # 总页数
    }

    # 传入模板渲染
    return render_template("news/user_collection.html", data=data)


# 新闻发布
@user_blu.route("/news_release", methods=['GET', 'POST'])
@user_login_data
def news_release():
    user = g.user
    if not user:  # 判断用户登录
        return abort(403)

    # GET展示数据
    if request.method == "GET":
        # 查询所有的分类数据
        try:
            # 获取所有分类
            categories = Category.query.all()
        except BaseException as e:
            current_app.logger.error(e)
            return abort(500)

        if len(categories):
            categories.pop(0)  # 删除"最新"数据

        # 模板渲染
        return render_template("news/user_news_release.html", categories=categories)

    # POST请求
    title = request.form.get("title")
    category_id = request.form.get("category_id")
    digest = request.form.get("digest")
    content = request.form.get("content")
    index_image = request.files.get("index_image")

    # 校验参数
    if not all([title, category_id, digest, content, index_image]):
        return jsonify(errno=RET.PARAMERR, errmsg=error_map[RET.PARAMERR])

    # 生成新闻模型
    news = News()
    news.title = title
    news.category_id = category_id
    news.digest = digest
    news.content = content
    try:
        # 读取图片二进制
        img_bytes = index_image.read()
        # 七牛云
        file_name = file_upload(img_bytes)
        # 在models.py中拼接七牛地址
        news.index_image_url = QINIU_DOMIN_PREFIX + file_name
    except BaseException as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.PARAMERR, errmsg=error_map[RET.PARAMERR])

    # 设置其他属性
    news.source = "个人发布"
    news.user_id = user.id
    news.status = 1  # 待审核状态

    # 添加到数据库
    db.session.add(news)

    return jsonify(errno=RET.OK, errmsg=error_map[RET.OK])


# 我的发布
@user_blu.route("/news_list")
@user_login_data
def news_list():
    user = g.user
    if not user:  # 判断用户是否登录
        return abort(403)

    # 获取参数获取请求的第几页  默认为1
    p = request.args.get("p", 1)
    # 校验参数
    try:
        p = int(p)
    except BaseException as e:
        current_app.logger.error(e)
        return abort(403)

    # 查询该用户发布的所有新闻　发布时间倒序
    try:
        # 用户发布的新闻已经存在列表中 多了字段通过关系属性
        pn = user.news_list.order_by(News.create_time.desc()).paginate(p, USER_COLLECTION_MAX_NEWS)
    except BaseException as e:
        current_app.logger.error(e)

    # 转换数据
    data = {
        "news_list": [news.to_review_dict() for news in pn.items],  # 取出所有数据放到列表中，传给页面遍历
        "cur_page": pn.page,  # 当前页码
        "total_page": pn.pages  # 总页数
    }

    # 传入模板渲染
    return render_template("news/user_news_list.html", data=data)


# 我的关注
@user_blu.route("/user_follow")
@user_login_data
def user_follow():
    user = g.user
    if not user:  # 判断用户是否登录
        return abort(403)

    # 获取参数获取请求的第几页  默认为1
    p = request.args.get("p", 1)
    # 校验参数
    try:
        p = int(p)
    except BaseException as e:
        current_app.logger.error(e)
        return abort(403)

    # 查询该用户关注的所有作者　
    try:
        # 分页pafinate(当前页，每页几条) 分页后是个pn对像
        pn = user.followed.paginate(p, USER_COLLECTION_MAX_NEWS)
    except BaseException as e:
        current_app.logger.error(e)

    # 转换数据
    data = {
        "author_list": [user.to_dict() for user in pn.items],
        "cur_page": pn.page,  # 当前页码
        "total_page": pn.pages  # 总页数
    }

    # 传入模板渲染
    return render_template("news/user_follow.html", data=data)
